/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_video.h"
#include "../SDL_pixels_c.h"

#include "SDL_cellvideo.h"

#include <cell/pad.h>
#include <cell/mouse.h>
#include <cell/keyboard.h>

#ifdef CELL_SHADER_SUPPORT
#pragma comment (lib,"PSGLcgc")
#pragma comment (lib,"cgc")
#endif

/* Surface Info */
#include <PSGL/psgl.h>

struct SDL_PrivateVideoData	CELL_Video;

/* SDL Driver Functions */
static int				CELL_Available			(void) {return(1);}
extern void				CELL_InitOSKeymap		(_THIS);
extern void				CELL_PumpEvents			(_THIS);
static int				CELL_VideoInit			(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect**		CELL_ListModes			(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface*		CELL_SetVideoMode		(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static void				CELL_VideoQuit			(_THIS) {};

/* SDL Driver functions [defined + implement] */
static int				CELL_AllocHWSurface		(_THIS, SDL_Surface *surface) {return(-1);}
static void				CELL_FreeHWSurface		(_THIS, SDL_Surface *surface) {return;}
extern int				CELL_LockHWSurface		(_THIS, SDL_Surface *surface);
extern void				CELL_UnlockHWSurface	(_THIS, SDL_Surface *surface);
static int				CELL_SetColors			(_THIS, int firstcolor, int ncolors, SDL_Color *colors) {return 1;}
extern int				CELL_FillHWRect			(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);

static int				CELL_FlipHWSurface		(_THIS, SDL_Surface *surface)
{
	CELL_PSGL_Update(this);
	return 0;
}
static void				CELL_UpdateRects		(_THIS, int numrects, SDL_Rect *rects) {CELL_FlipHWSurface(this, 0);} //HACK


/*********IMPLEMENTATIONS***************/
static void				CELL_DeleteDevice		(SDL_VideoDevice *device)
{
	CELL_RC_DumpData();

#ifndef CELL_NO_SOFT_INPUT
	CELL_CURSOR_Free(0, CELL_Video.OSK.Cursor);
#endif

	CELL_PSGL_Kill(device);

	SDL_free(device);

	cellKbEnd();
	cellMouseEnd();
	cellPadEnd();
}

static SDL_VideoDevice*	CELL_CreateDevice		(int devindex)
{
	/* Allocate memory for sdl video device */
	CELL_VideoDevice = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
	if(CELL_VideoDevice)
	{
		SDL_memset(CELL_VideoDevice, 0, (sizeof *CELL_VideoDevice));
		CELL_VideoDevice->hidden = &CELL_Video;
		SDL_memset(&CELL_Video, 0, sizeof(CELL_Video));
	}
	else
	{
		SDL_OutOfMemory();
		return(0);
	}

	/* Set the function pointers */
	//General
	CELL_VideoDevice->VideoInit = CELL_VideoInit;
	CELL_VideoDevice->ListModes = CELL_ListModes;
	CELL_VideoDevice->SetVideoMode = CELL_SetVideoMode;
	//ToggleFullScreen(this, int on)
	//UpdateMouse(this)
	//SDL_Overlay *(*CreateYUVOverlay)(_THIS, int width, int height, Uint32 format, SDL_Surface *display);
	CELL_VideoDevice->SetColors = CELL_SetColors;
	CELL_VideoDevice->UpdateRects = CELL_UpdateRects;
	CELL_VideoDevice->VideoQuit = CELL_VideoQuit;

	//Accel
	CELL_VideoDevice->AllocHWSurface = CELL_AllocHWSurface;
	//int (*CheckHWBlit)(_THIS, SDL_Surface *src, SDL_Surface *dst);
	CELL_VideoDevice->FillHWRect = CELL_FillHWRect;
	//int (*SetHWColorKey)(_THIS, SDL_Surface *surface, Uint32 key);
	//int (*SetHWAlpha)(_THIS, SDL_Surface *surface, Uint8 value);
	CELL_VideoDevice->LockHWSurface = CELL_LockHWSurface;
	CELL_VideoDevice->UnlockHWSurface = CELL_UnlockHWSurface;
	CELL_VideoDevice->FlipHWSurface = CELL_FlipHWSurface;
	CELL_VideoDevice->FreeHWSurface = CELL_FreeHWSurface;

	//Gamma
	//int (*SetGamma)(_THIS, float red, float green, float blue);
	//int (*GetGamma)(_THIS, float *red, float *green, float *blue);
	//int (*SetGammaRamp)(_THIS, Uint16 *ramp);
	//int (*GetGammaRamp)(_THIS, Uint16 *ramp);

	//OpenGL
	//int (*GL_LoadLibrary)(_THIS, const char *path);
	//void* (*GL_GetProcAddress)(_THIS, const char *proc);
	//int (*GL_GetAttribute)(_THIS, SDL_GLattr attrib, int* value);
	//int (*GL_MakeCurrent)(_THIS);
	//void (*GL_SwapBuffers)(_THIS);

	//Window manager
	CELL_VideoDevice->SetCaption = CELL_CAPTION_Set;
	//void (*SetIcon)(_THIS, SDL_Surface *icon, Uint8 *mask);
	//int (*IconifyWindow)(_THIS);
	//SDL_GrabMode (*GrabInput)(_THIS, SDL_GrabMode mode);
	//int (*GetWMInfo)(_THIS, SDL_SysWMinfo *info);

	//Cursor
	CELL_VideoDevice->FreeWMCursor = CELL_CURSOR_Free;
	CELL_VideoDevice->CreateWMCursor = CELL_CURSOR_Create;
	CELL_VideoDevice->ShowWMCursor = CELL_CURSOR_Show;
	//void (*WarpWMCursor)(_THIS, Uint16 x, Uint16 y);
	CELL_VideoDevice->MoveWMCursor = CELL_CURSOR_Move;
	//void (*CheckMouseMode)(_THIS);

	//Events
	CELL_VideoDevice->InitOSKeymap = CELL_EVENTS_Init;
	CELL_VideoDevice->PumpEvents = CELL_EVENTS_Pump;

	//Clean up
	CELL_VideoDevice->free = CELL_DeleteDevice;

	/* Initialize CELL input libs */
	cellKbInit(1);
	cellMouseInit(1);
	cellPadInit(7);

	/* Setup PSGL */
	CELL_PSGL_Setup(CELL_VideoDevice);

	/* Read the RC File */
	CELL_RC_GetData();
	return CELL_VideoDevice;
}

int CELL_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
	vformat->BitsPerPixel = 32;
	vformat->BytesPerPixel = 4;

	/* Set some capabilities */
	this->handles_any_size = 1;
	this->info.video_mem = 224 * 1024;

	/* HACK: Just say 1024x768 for now */
	this->info.current_w = 1024;
	this->info.current_h = 768;

	this->info.blit_fill = 1;

	return(0);
}

SDL_Rect **CELL_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
	/* We only support 32-bit mode */
	/* TODO: Will this really work ? */
	if(format && format->BitsPerPixel != 32)
	{
		return 0;
	}

	return (SDL_Rect**)-1;

#if 0
	/* TODO: Report some video modes, we never actually change the screen resolution.
	   Instead we scale our image to whatever the screen is set to by default.
	   Still, for information purposes for the app we should probably report only 
	   resolutions smaller than the screen */
	static SDL_Rect PS3_resolutions[] =
	{
		{0, 0, 1920, 1080},
		{0, 0, 1600, 1200},
		{0, 0, 1600, 900},
		{0, 0, 1366, 768},
		{0, 0, 1280, 1024},
		{0, 0, 1280, 720},
		{0, 0, 1024, 768},
		{0, 0, 800, 600},
		{0, 0, 720, 576},
		{0, 0, 720, 480},
		{0, 0, 640, 480},
		{0, 0, 320, 240},
		{0, 0, 320, 200}
	};

	/*  Allocate the rect areas and return em */
	static SDL_Rect *PS3_modes[sizeof(PS3_resolutions) / sizeof(SDL_Rect) + 1];
	for(int i = 0; i != sizeof(PS3_resolutions) / sizeof(SDL_Rect); i ++)
	{
		PS3_modes[i] = &PS3_resolutions[i];
	}
	PS3_modes[sizeof(PS3_resolutions) / sizeof(SDL_Rect)] = 0;
	return (SDL_Rect**)PS3_modes;
#endif
}

SDL_Surface *CELL_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags)
{
	/* Copy the video size into the device */
	this->hidden->VideoMode.Width = width;
	this->hidden->VideoMode.Height = height;

	/* Update PSGL settings */
	if(0 > CELL_PSGL_SetMode(this, current))
	{
		/* PSGL Update failed */
		return 0;
	}

	/* Allocate the new pixel format for the screen */
	if(!SDL_ReallocFormat(current, 32, 0, 0, 0, 0))
	{
		SDL_SetError("Couldn't allocate new pixel format for requested mode");
		return 0;
	}

	/* Set up the new mode framebuffer */
	/* TODO: What should we really return in flags? SDL_NOFRAME | SDL_FULLSCREEN | SDL_ASYNCBLIT ?*/
	current->flags = flags | SDL_HWSURFACE;
	current->w = width;
	current->h = height;
	current->pitch = current->w * 4;
	current->pixels = 0;

	/* We're done */
	return(current);
}

VideoBootStrap			CELL_bootstrap	=		{"Cell", "Cell video driver", CELL_Available, CELL_CreateDevice};

